############# ########### ####### ##### ### ##
#
# Copyright (C) 2010 The Hursk Group, LLC
#
# This program is free software: you can redistribute it and/or modify 
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program (See file named COPYING).  If not, see 
# <http://www.gnu.org/licenses/>.
# 
############# ########### ####### ##### ### ##

#!/usr/bin/perl
# 1.) RUN FROM WINDOWS DIRECTORY CONTAINING HOSTS and
# 2.) CHANGE THE FOLLOWING OUTPUT_ENV VAR to the directory where you want output.txt to be appended to:
#     (make sure there is NOT a backslash on the end of the path)

use strict;
use File::Find;
use Digest::MD5;

our @dirs = `ls -1d */`;
our @hostnames = get_hostnames();
our @hostnames_that_have_this_file;
our %file_record = build_file_record();
our $file; #The current file we are looking for, globally-defined
our $value; #File value we are looking for
our $line; #The current line we are looking for, globally-defined

foreach my $keyvalue (sort keys(%file_record))
{
    my @keyvalue = split /\|/, $keyvalue;
    $file = $keyvalue[0];
    $value = $file_record{$keyvalue}; 
    
    find(\&wanted, @dirs);
    
    #Stringify @hostnames_that_have_this_file;
    my $hostnames_that_have_this_file = "@hostnames_that_have_this_file";
    foreach my $host (@hostnames)
    {
        #If a given host in all of @hostnames is found, then great, but if it's
        #not found, then print a finding that the file was not found for the given host:
        if ($hostnames_that_have_this_file =~ /$host/) 
        {
            next;
        }
        else
        {
            my $output = "$host, File $file not found\n";
            print $output;
        }
    }
    undef @hostnames_that_have_this_file; #Clear this baby out for the next iteration of foreach $file
}

#SUB: wanted
#PARAM; $file - the file we're looking for
#FUNC: Traverses through directory structure, examining each file and dir
sub wanted {
    
    # $_ is the current file we're looking at, and $file is the file we're looking for, and
    # $File::Find::dir is the directory we're in:
    if ($_ =~ /^$file$/)
    {
        my $hostname;
        #If the hostname has a backslash or forwardslash....
        if ($File::Find::dir =~ /\/|\\/)
        {
            #...then split it by the backslash or forwardslash:
            my @hostname_string = split /\/|\\/, $File::Find::dir;
            
            #The hostname is the first element of the @hostname_string:
            $hostname = shift @hostname_string;
        }
        else
        {
            #Otherwise, if there is no backslash or forwardslash,
            #and $hostname is simply == $File::Find::dir
            $hostname = $File::Find::dir;
        }
        push @hostnames_that_have_this_file, $hostname;#this hostname has this file
        
        my @lines_to_search = split /,/, $value;
        $lines_to_search[0] =~ s/^\s+//; $lines_to_search[0] =~ s/\s+$//; #Trim whitespace on front and back of string
        if ($lines_to_search[1]){$lines_to_search[1] =~ s/^\s+//; $lines_to_search[1] =~ s/\s+$//;}
        
        undef $_; undef $line;
        my $file_location = $File::Find::name;
        
        my $line_counter =0;
        my $number_of_lines =1;
        my $found = 0;
        open FHA, "<", "$file";
        while (<FHA>)
        {
            chomp $_; 
            if ($found ==0 && $_ =~ /^\s*$lines_to_search[0]/)
            {
                if ($_ =~ /^\s*#/)
                {
                    next;
                }
                else
                {
                    $line = $_;
                    $found = 1;
                }
            }
            elsif ($found == 1 && $lines_to_search[1] && $line_counter < $number_of_lines)
            {
                if ($_ =~ /^\s*#/)
                {
                    next;
                }
                else
                {
                    $number_of_lines = $lines_to_search[1];
                    
                    $line = "$line"." $_"; #Append $_ to $line separated with a space
                    $line_counter++;
                }
            }
        }#END while
        close FHA;
        
        $_ = $file_location;
        s/$hostname\///;
        my $file_dir = $_;
        
        if ($line =~ /.*".*/) #If the line has any quotes whatsoever, delete them
        {
            $_ = $line;
            s/(")//g; #Delete all quotes in $line
            $line = $_;
        }
        
        if (!defined($line))
        {
            my $finding = $lines_to_search[0];
            $line = "Content \"$finding\" not found";
            
            my $output = "$hostname, $file_location, $line\n"; #No need to print MD5 since Contents not found
            print $output;
        }
        elsif ($line =~ /(^\s*$)/) #If $line > 0 spaces (the line is blank)
        {
            my $finding = $lines_to_search[0];
            $line = "Content \"$finding\" not found";
            
            my $output = "$hostname, $file_location, $line\n"; #No need to print MD5 since Contents not found
            print $output;
        }
        elsif ($line =~ /(^.*,.*$)/) #If there are any commas in the line, put the whole line in quotes
        {
            $line = "\"$line\"";
            
            my $md5hash = "$file, $line";
            $md5hash = Digest::MD5::md5_hex($md5hash);
            my $output = "$hostname, $file_location, $line, $md5hash\n";
            print $output;
        }
        else
        {
            my $md5hash = "$file, $line";
            $md5hash = Digest::MD5::md5_hex($md5hash);
            my $output = "$hostname, $file_location, $line, $md5hash\n";
            print $output;
        }
    }

}

#SUB: build_file_record
#PARAM: none
#RETURNS: %file_record
#FUNC: returns hash record with the following key-value pairs:
#       $file_record{$file_name} = $pertinent_line
sub build_file_record{
    open FH, "<", "file_record";
    while (<FH>)
    {
        chomp $_;#Clear endline char from line
        my @record = split /,/;
        my $value1; my $value2; my $value3; my $value4; my $value5; my $value6; my $value7; my $value8; my $value9; my $value10; 
        my $key = $record[0]; $key =~ s/^\s+//; $key =~ s/\s+$//; #Trim whitespace from the front and back of string:
        $value1 = $record[1]; $value1 =~ s/^\s+//; $value1 =~ s/\s+$//;
        if ($record[2]){$value2 = $record[2]; $value2 =~ s/^\s+//; $value2 =~ s/\s+$//; $value2 = ", $value2";}
        if ($record[3]){$value3 = $record[3]; $value3 =~ s/^\s+//; $value3 =~ s/\s+$//; $value3 = ", $value3";}
        if ($record[4]){$value4 = $record[4]; $value4 =~ s/^\s+//; $value4 =~ s/\s+$//; $value4 = ", $value4";}
        if ($record[5]){$value5 = $record[5]; $value5 =~ s/^\s+//; $value5 =~ s/\s+$//; $value5 = ", $value5";}
        if ($record[6]){$value6 = $record[6]; $value6 =~ s/^\s+//; $value6 =~ s/\s+$//; $value6 = ", $value6";}
        if ($record[7]){$value7 = $record[7]; $value7 =~ s/^\s+//; $value7 =~ s/\s+$//; $value7 = ", $value7";}
        if ($record[8]){$value8 = $record[8]; $value8 =~ s/^\s+//; $value8 =~ s/\s+$//; $value8 = ", $value8";}
        if ($record[9]){$value9 = $record[9]; $value9 =~ s/^\s+//; $value9 =~ s/\s+$//; $value9 = ", $value9";}
        if ($record[10]){$value10 = $record[10]; $value10 =~ s/^\s+//; $value10 =~ s/\s+$//; $value10 = ", $value10";}
        
        my $val = "$value1$value2$value3$value4$value5$value6$value7$value8$value9$value10";
        my $keyval = "$key|$val";#Make it unique.
        
        $file_record{$keyval} = $val; #Insert record
    }
    close FH;
    return %file_record;
}

#SUB: get_hostnames
#PARAM: none
#FUNC: returns list of hostnames
#RETURNS: @hostnames
sub get_hostnames{
    my @hostnames;
    foreach my $dir (@dirs)
    {
        chomp $dir;
        unless ($dir =~ /output/)
        {
            $_ = $dir; s/\///; $dir = $_;#Take off trailing "/" on $dir
            my $hostn = $dir; #Set hostname
            push @hostnames, $hostn;
        }
    }
    return @hostnames;
}

